package com.example.demo.filter;

import com.example.demo.entity.SysMenu;
import com.example.demo.entity.SysRole;
import com.example.demo.service.JwtUserDetailService;
import com.example.demo.utils.JwtTokenUtil;
import com.example.demo.utils.JwtUserDetails;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * @Author: zengzr
 * @Date: 2019/3/27
 * @Description: 过滤器
 */

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private JwtUserDetailService userDetailService;

    private String tokenHeader;

    private String tokenHead = "Bearer ";

    private JwtTokenUtil jwtTokenUtil;

    private RedisTemplate redisTemplate;


    public JwtAuthenticationTokenFilter(JwtTokenUtil jwtTokenUtil,String tokenHeader,JwtUserDetailService userDetailService){
        this.jwtTokenUtil = jwtTokenUtil;
        this.tokenHeader = tokenHeader;
        this.userDetailService = userDetailService;
        this.redisTemplate = new StringRedisTemplate();
    }

    private static List<String> skipUrl = new ArrayList<>();

    static {
        skipUrl.add("/auth/login");
        skipUrl.add("OPTIONS");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

        String servletPath = request.getServletPath();
        String method = request.getMethod();
        if (skipUrl.contains(servletPath) || skipUrl.contains(method)) {
            chain.doFilter(request, response);
            return;
        }
        String authHeader = request.getHeader(this.tokenHeader);
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            final String authToken = authHeader.substring(tokenHead.length());
            String username = jwtTokenUtil.getUsernameFromToken(authToken);
            if (username != null) {
                UserDetails userDetails = this.userDetailService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(authToken, userDetails) && this.authentication(servletPath, (JwtUserDetails) userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    try {
                        chain.doFilter(request, response);
                        return;
                    } catch (Exception e) {
                        response.setContentType("application/json;charset=UTF-8");
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        PrintWriter out = response.getWriter();
                        out.println("请求异常");
                        out.flush();
                        out.close();
                    }
                }
                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                PrintWriter out = response.getWriter();
                out.println(HttpServletResponse.SC_UNAUTHORIZED);
                out.flush();
                out.close();
            }
        }
    }

    private boolean authentication(String servletPath, JwtUserDetails userDetails) {
        //判断角色对应的url
        Set<String> paths = new HashSet<>();
        Set<SysRole> roles = userDetails.getSysRols();
        Iterator role = roles.iterator();
        while (role.hasNext()){
            SysRole sysRole = (SysRole) role.next();
            Set<SysMenu> menus = sysRole.getMenus();
            Iterator menu = menus.iterator();
            while (menu.hasNext()){
                SysMenu sysMenu = (SysMenu) menu.next();
                paths.add(sysMenu.getMenuUrl());
            }
        }
        return paths.contains(servletPath);
    }
}
